package top.lshaci.learning.nio.zerocopy;

import lombok.extern.slf4j.Slf4j;

import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;

/**
 * NewIOClient
 *
 * @author lshaci
 * @since 1.0.0
 */
@Slf4j
public class NewIOClient {

    private static final long _8M = 8 * 1024 * 1024;

    public static void main(String[] args) throws IOException {
        SocketChannel client = SocketChannel.open();
        client.connect(new InetSocketAddress("127.0.0.1", 6688));
//        String filename = "F:\\System\\Pictures\\background\\-220f944a8e69fcad.jpg";
        String filename = "F:\\迅雷下载\\Docker Desktop Installer.exe"; // 960472784
        FileChannel fileChannel = new FileInputStream(filename).getChannel();
        long transferCount = fileChannel.size();

        long start = System.currentTimeMillis();
        // 在 linux 下, 一个 transferTo 方法就可以完成传输
        // 在 windows 下, 一次调用 transferTo 只能发送 8M, 就需要分段传输文件，而且要注意传输时的位置
        // transferTo 底层使用到零拷贝
        String os = System.getProperty("os.name").toLowerCase();
        if ("linux".equalsIgnoreCase(os)) {
            linux(client, fileChannel);
        } else {
            windows(client, fileChannel);
        }

        long end = System.currentTimeMillis();

        log.debug("发送的总字节数: {}, 耗时: {} ms", transferCount, (end - start));
    }

    public static void linux(SocketChannel client, FileChannel fileChannel) throws IOException {
        fileChannel.transferTo(0, fileChannel.size(), client);
    }

    public static void windows(SocketChannel client, FileChannel fileChannel) throws IOException {
        long fileSize = fileChannel.size();
        long times = (fileSize + _8M - 1) / _8M;
        log.info("总数据量大小为: {}, 需要发送 {} 次", fileSize, times);
        long count = 0;
        for (int i = 0; i < times; i++) {
            long read = fileChannel.transferTo(_8M * i, _8M, client);
            log.debug("第 {} 次发送, 数据量: {}", i + 1, read);
            count += read;
        }
        log.info("一共发送了 {} 字节", count);
    }
}
